# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details
###############################################################################
# This file contains driver test information for DXIL operations              #
###############################################################################

from hctdb import *
import xml.etree.ElementTree as ET
import argparse

parser = argparse.ArgumentParser(description="contains information about dxil op test cases.")
parser.add_argument('mode', help="'gen-xml' or 'info'")

g_db_dxil = None

def get_db_dxil():
    global g_db_dxil
    if g_db_dxil is None:
        g_db_dxil = db_dxil()
    return g_db_dxil

"""
This class represents a test case for instructions for driver testings

DXIL instructions and test cases are two disjoint sets where each instruction can have multiple test cases,
and each test case can cover different DXIL instructions. So these two sets form a bipartite graph.

test_name: Test case identifier. Must be unique for each test case.
insts: dxil instructions
validation_type: validation type for test
    epsilon: absolute difference check
    ulp: units in last place check
    relative: relative error check
validation_tolerance: tolerance value for a given test
inputs: testing inputs
outputs: expected outputs for each input
shader_target: target for testing
shader_text: hlsl file that is used for testing dxil op
"""

class test_case(object):
    def __init__(self, test_name, insts, validation_type, validation_tolerance,
                 input_lists, output_lists, shader_target, shader_text, **kwargs):
        self.test_name = test_name
        self.validation_type = validation_type
        self.validation_tolerance = validation_tolerance
        self.input_lists = input_lists
        self.output_lists = output_lists
        self.shader_target = shader_target
        self.shader_text = shader_text
        self.insts = insts # list of instructions each test case cover
        self.warp_version = -1 # known warp version that works
        self.shader_arguments = ""
        for k,v in kwargs.items():
            setattr(self, k, v)

# Wrapper for each DXIL instruction
class inst_node(object):
    def __init__(self, inst):
        self.inst = inst
        self.test_cases = []  # list of test_case

def add_test_case(test_name, inst_names, validation_type, validation_tolerance,
                  input_lists, output_lists, shader_target, shader_text, **kwargs):
    insts = []
    for inst_name in inst_names:
        assert (inst_name in g_instruction_nodes)
        insts += [g_instruction_nodes[inst_name].inst]
    case = test_case(test_name, insts, validation_type,
                    validation_tolerance, input_lists, output_lists,
                    shader_target, shader_text, **kwargs)
    g_test_cases[test_name] = case
    # update instruction nodes
    for inst_name in inst_names:
        g_instruction_nodes[inst_name].test_cases += [case]

def add_test_case_int(test_name, inst_names, validation_type, validation_tolerance,
                  input_lists, output_lists, shader_key, shader_op_name, **kwargs):
    add_test_case(test_name, inst_names, validation_type, validation_tolerance,
                  input_lists, output_lists, "cs_6_0", get_shader_text(shader_key, shader_op_name), **kwargs)
    input_lists_16, output_lists_16 = input_lists, output_lists
    if "input_16" in kwargs:
        input_lists_16 = kwargs["input_16"]
    if "output_16" in kwargs:
        output_lists_16 = kwargs["output_16"]
    add_test_case(test_name + "Bit16", inst_names, validation_type, validation_tolerance,
                  input_lists_16, output_lists_16, "cs_6_2", get_shader_text(shader_key.replace("int","int16_t"), shader_op_name),
                  shader_arguments="-enable-16bit-types", **kwargs)

def add_test_case_float_half(test_name, inst_names, validation_type, validation_tolerance,
                  float_input_lists, float_output_lists, shader_key, shader_op_name, **kwargs):
    add_test_case(test_name, inst_names, validation_type, validation_tolerance,
                  float_input_lists, float_output_lists, "cs_6_0", get_shader_text(shader_key, shader_op_name), **kwargs)
    # if half test cases are different from float input lists, use those lists instead for half testings
    half_input_lists, half_output_lists, half_validation_type, half_validation_tolerance = float_input_lists, float_output_lists, validation_type, validation_tolerance
    if "half_inputs" in kwargs:
        half_input_lists = kwargs["half_inputs"]
    if "half_outputs" in kwargs:
        half_output_lists = kwargs["half_outputs"]
    if "half_validation_type" in kwargs:
        half_validation_type = kwargs["half_validation_type"]
    if "half_validation_tolerance" in kwargs:
        half_validation_tolerance = kwargs["half_validation_tolerance"]
    # skip relative error test check for half for now
    if validation_type != "Relative":
        add_test_case(test_name + "Half", inst_names, half_validation_type, half_validation_tolerance,
                    half_input_lists, half_output_lists, "cs_6_2",
                    get_shader_text(shader_key.replace("float","half"), shader_op_name), shader_arguments="-enable-16bit-types", **kwargs)

def add_test_case_denorm(test_name, inst_names, validation_type, validation_tolerance, input_lists,
                    output_lists_ftz, output_lists_preserve, shader_target, shader_text, **kwargs):
    add_test_case(test_name + "FTZ", inst_names, validation_type, validation_tolerance, input_lists,
                  output_lists_ftz, shader_target, shader_text, shader_arguments="-denorm ftz")
    add_test_case(test_name + "Preserve", inst_names, validation_type, validation_tolerance, input_lists,
                  output_lists_preserve, shader_target, shader_text, shader_arguments="-denorm preserve")
    # we can expect the same output for "any" and "preserve" mode. We should make sure that for validation zero are accepted outputs for denormal outputs.
    add_test_case(test_name + "Any", inst_names, validation_type, validation_tolerance, input_lists,
                  output_lists_preserve + output_lists_ftz, shader_target, shader_text, shader_arguments="-denorm any")


g_shader_texts = {
    "unary int": ''' struct SUnaryIntOp {
                int input;
                int output;
            };
            RWStructuredBuffer<SUnaryIntOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryIntOp l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary int16_t": ''' struct SUnaryInt16Op {
                int16_t input;
                int16_t output;
            };
            RWStructuredBuffer<SUnaryInt16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryInt16Op l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary uint": ''' struct SUnaryUintOp {
                uint input;
                uint output;
            };
            RWStructuredBuffer<SUnaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryUintOp l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary uint16_t": ''' struct SUnaryUint16Op {
                uint16_t input;
                uint16_t output;
            };
            RWStructuredBuffer<SUnaryUint16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryUint16Op l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary float": ''' struct SUnaryFPOp {
                float input;
                float output;
            };
            RWStructuredBuffer<SUnaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryFPOp l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary float bool": ''' struct SUnaryFPOp {
                float input;
                float output;
            };
            RWStructuredBuffer<SUnaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryFPOp l = g_buf[GI];
                if (%s(l.input))
                    l.output = 1;
                else
                    l.output = 0;
                g_buf[GI] = l;
            };''',

    "unary half": ''' struct SUnaryFPOp {
                float16_t input;
                float16_t output;
            };
            RWStructuredBuffer<SUnaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryFPOp l = g_buf[GI];
                l.output = %s(l.input);
                g_buf[GI] = l;
            };''',

    "unary half bool": ''' struct SUnaryFPOp {
                float16_t input;
                float16_t output;
            };
            RWStructuredBuffer<SUnaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SUnaryFPOp l = g_buf[GI];
                if (%s(l.input))
                    l.output = 1;
                else
                    l.output = 0;
                g_buf[GI] = l;
            };''',

     "binary int": ''' struct SBinaryIntOp {
                int input1;
                int input2;
                int output1;
                int output2;
            };
            RWStructuredBuffer<SBinaryIntOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryIntOp l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

     "binary int16_t": ''' struct SBinaryInt16Op {
                int16_t input1;
                int16_t input2;
                int16_t output1;
                int16_t output2;
            };
            RWStructuredBuffer<SBinaryInt16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryInt16Op l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

    "binary int call": ''' struct SBinaryIntOp {
                int input1;
                int input2;
                int output1;
                int output2;
            };
            RWStructuredBuffer<SBinaryIntOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryIntOp l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

    "binary int16_t call": ''' struct SBinaryInt16Op {
                int16_t input1;
                int16_t input2;
                int16_t output1;
                int16_t output2;
            };
            RWStructuredBuffer<SBinaryInt16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryInt16Op l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

    "binary uint": ''' struct SBinaryUintOp {
                uint input1;
                uint input2;
                uint output1;
                uint output2;
            };
            RWStructuredBuffer<SBinaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUintOp l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

    "binary uint16_t": ''' struct SBinaryUint16Op {
                uint16_t input1;
                uint16_t input2;
                uint16_t output1;
                uint16_t output2;
            };
            RWStructuredBuffer<SBinaryUint16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUint16Op l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

    "binary uint call": ''' struct SBinaryUintOp {
                uint input1;
                uint input2;
                uint output1;
                uint output2;
            };
            RWStructuredBuffer<SBinaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUintOp l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

    "binary uint16_t call": ''' struct SBinaryUint16Op {
                uint16_t input1;
                uint16_t input2;
                uint16_t output1;
                uint16_t output2;
            };
            RWStructuredBuffer<SBinaryUint16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUint16Op l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

    "binary float": ''' struct SBinaryFPOp {
                float input1;
                float input2;
                float output1;
                float output2;
            };
            RWStructuredBuffer<SBinaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryFPOp l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

    "binary float call": ''' struct SBinaryFPOp {
                float input1;
                float input2;
                float output1;
                float output2;
            };
            RWStructuredBuffer<SBinaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryFPOp l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

    "binary half": ''' struct SBinaryFPOp {
                half input1;
                half input2;
                half output1;
                half output2;
            };
            RWStructuredBuffer<SBinaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryFPOp l = g_buf[GI];
                l.output1 = l.input1 %s l.input2;
                g_buf[GI] = l;
            };''',

    "binary half call": ''' struct SBinaryFPOp {
                half input1;
                half input2;
                half output1;
                half output2;
            };
            RWStructuredBuffer<SBinaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryFPOp l = g_buf[GI];
                l.output1 = %s(l.input1,l.input2);
                g_buf[GI] = l;
            };''',

     "tertiary int": ''' struct STertiaryIntOp {
                int input1;
                int input2;
                int input3;
                int output;
            };
            RWStructuredBuffer<STertiaryIntOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryIntOp l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',

     "tertiary int16_t": ''' struct STertiaryInt16Op {
                int16_t input1;
                int16_t input2;
                int16_t input3;
                int16_t output;
            };
            RWStructuredBuffer<STertiaryInt16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryInt16Op l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',

     "tertiary uint": ''' struct STertiaryUintOp {
                uint input1;
                uint input2;
                uint input3;
                uint output;
            };
            RWStructuredBuffer<STertiaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryUintOp l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',

     "tertiary uint16_t": ''' struct STertiaryUint16Op {
                uint16_t input1;
                uint16_t input2;
                uint16_t input3;
                uint16_t output;
            };
            RWStructuredBuffer<STertiaryUint16Op> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryUint16Op l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',

    "tertiary float": ''' struct STertiaryFloatOp {
                float input1;
                float input2;
                float input3;
                float output;
            };
            RWStructuredBuffer<STertiaryFloatOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryFloatOp l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',
    'tertiary half': ''' struct STertiaryHalfOp {
                half input1;
                half input2;
                half input3;
                half output;
            };
            RWStructuredBuffer<STertiaryHalfOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                STertiaryHalfOp l = g_buf[GI];
                l.output = %s(l.input1, l.input2, l.input3);
                g_buf[GI] = l;
            };''',
    "wave op int" :''' struct PerThreadData {
                        uint firstLaneId;
                        uint laneIndex;
                        int mask;
                        int input;
                        int output;
                    };
                    RWStructuredBuffer<PerThreadData> g_sb : register(u0);
                    [numthreads(8,12,1)]
                    void main(uint GI : SV_GroupIndex) {
                        PerThreadData pts = g_sb[GI];
                        pts.firstLaneId = WaveReadLaneFirst(GI);
                        pts.laneIndex = WaveGetLaneIndex();
                        if (pts.mask != 0) {
                            pts.output = %s(pts.input);
                        }
                        else {
                            pts.output = %s(pts.input);
                        }
                        g_sb[GI] = pts;
                    };''',
    "wave op uint" :''' struct PerThreadData {
                        uint firstLaneId;
                        uint laneIndex;
                        int mask;
                        uint input;
                        uint output;
                    };
                    RWStructuredBuffer<PerThreadData> g_sb : register(u0);
                    [numthreads(8,12,1)]
                    void main(uint GI : SV_GroupIndex) {
                        PerThreadData pts = g_sb[GI];
                        pts.firstLaneId = WaveReadLaneFirst(GI);
                        pts.laneIndex = WaveGetLaneIndex();
                        if (pts.mask != 0) {
                            pts.output = %s(pts.input);
                        }
                        else {
                            pts.output = %s(pts.input);
                        }
                        g_sb[GI] = pts;
                    };''',
    "wave op int count": ''' struct PerThreadData {
                        uint firstLaneId;
                        uint laneIndex;
                        int mask;
                        int input;
                        int output;
                    };
                    RWStructuredBuffer<PerThreadData> g_sb : register(u0);
                    [numthreads(8,12,1)]
                    void main(uint GI : SV_GroupIndex) {
                        PerThreadData pts = g_sb[GI];
                        pts.firstLaneId = WaveReadLaneFirst(GI);
                        pts.laneIndex = WaveGetLaneIndex();
                        if (pts.mask != 0) {
                            pts.output = %s(pts.input > 3);
                        }
                        else {
                            pts.output = %s(pts.input > 3);
                        }
                        g_sb[GI] = pts;
                    };''',
    "wave op multi prefix int": ''' struct ThreadData {
                    uint key;
                    uint firstLaneId;
                    uint laneId;
                    uint mask;
                    int value;
                    int result;
                };
                RWStructuredBuffer<ThreadData> g_buffer : register(u0);
                [numthreads(8, 12, 1)]
                void main(uint id : SV_GroupIndex) {
                    ThreadData data = g_buffer[id];
                    data.firstLaneId = WaveReadLaneFirst(id);
                    data.laneId = WaveGetLaneIndex();
                    if (data.mask != 0) {
                        uint4 mask = WaveMatch(data.key);
                        data.result = %s(data.value, mask);
                    } else {
                        uint4 mask = WaveMatch(data.key);
                        data.result = %s(data.value, mask);
                    }
                    g_buffer[id] = data;
                }''',
    "wave op multi prefix uint": ''' struct ThreadData {
                    uint key;
                    uint firstLaneId;
                    uint laneId;
                    uint mask;
                    uint value;
                    uint result;
                };
                RWStructuredBuffer<ThreadData> g_buffer : register(u0);
                [numthreads(8, 12, 1)]
                void main(uint id : SV_GroupIndex) {
                    ThreadData data = g_buffer[id];
                    data.firstLaneId = WaveReadLaneFirst(id);
                    data.laneId = WaveGetLaneIndex();
                    if (data.mask != 0) {
                        uint4 mask = WaveMatch(data.key);
                        data.result = %s(data.value, mask);
                    } else {
                        uint4 mask = WaveMatch(data.key);
                        data.result = %s(data.value, mask);
                    }
                    g_buffer[id] = data;
                }'''
}

def get_shader_text(op_type, op_call):
    assert(op_type in g_shader_texts)
    if op_type.startswith("wave op"):
        return g_shader_texts[op_type] % (op_call, op_call)
    return g_shader_texts[op_type] % (op_call)

g_denorm_tests = ["FAddDenormAny", "FAddDenormFTZ", "FAddDenormPreserve",
                "FSubDenormAny", "FSubDenormFTZ", "FSubDenormPreserve",
                "FMulDenormAny", "FMulDenormFTZ", "FMulDenormPreserve",
                "FDivDenormAny", "FDivDenormFTZ", "FDivDenormPreserve",
                "FMadDenormAny", "FMadDenormFTZ", "FMadDenormPreserve",
                "FAbsDenormAny", "FAbsDenormFTZ", "FAbsDenormPreserve",
                "FMinDenormAny", "FMinDenormFTZ", "FMinDenormPreserve",
                "FMaxDenormAny", "FMaxDenormFTZ", "FMaxDenormPreserve"]
# This is a collection of test case for driver tests per instruction
# Warning: For test cases, when you want to pass in signed 32-bit integer,
# make sure to pass in negative numbers with decimal values instead of hexadecimal representation.
# For some reason, TAEF is not handling them properly.
# For half values, hex is preferable since the test framework will read string as float values
# and convert them to float16, possibly losing precision. The test will read hex values as it is.
def add_test_cases():
    nan = float('nan')
    p_inf = float('inf')
    n_inf = float('-inf')
    p_denorm = float('1e-38')
    n_denorm = float('-1e-38')
    # Unary Float
    add_test_case_float_half('Sin', ['Sin'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-314.16',
        '314.16'
    ]], [[
        'NaN', 'NaN', '-0', '-0', '0', '0', 'NaN', '-0.0007346401',
        '0.0007346401'
    ]], "unary float", "sin", half_validation_tolerance=0.003, half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', 
        '0.6279297', '1.255859', '1.884766', '2.511719', '3.140625',
        '3.769531', '4.398438', '5.023438', '5.652344', '6.281250'
    ]], half_outputs=[[
        'NaN', 'NaN', '-0', '-0', '0', '0', 'NaN', 
        '0.58747065', '0.95081574', '0.95111507', '0.58904284', '0.00096773',
        '-0.58747751', '-0.95112079', '-0.95201313', '-0.58982444', '-0.00193545'
    ]])
    add_test_case_float_half('Cos', ['Cos'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-314.16',
        '314.16'
    ]], [[
        'NaN', 'NaN', '1.0', '1.0', '1.0', '1.0', 'NaN', '0.99999973015',
        '0.99999973015'
    ]], "unary float", "cos", half_validation_tolerance=0.003, half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', 
        '0.6279297', '1.255859', '1.884766', '2.511719', '3.140625',
        '3.769531', '4.398438', '5.023438', '5.652344', '6.281250'
    ]], half_outputs=[[
        'NaN', 'NaN', '1.0', '1.0', '1.0', '1.0', 'NaN', 
        '0.80924553', '0.30975693', '-0.30883664', '-0.80810183', '-0.99999952',
        '-0.80924052', '-0.30881903', '0.30605716', '0.80753154', '0.99999809'
    ]])
    add_test_case_float_half('Tan', ['Tan'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-314.16',
        '314.16'
    ]], [[
        'NaN', 'NaN', '-0.0', '-0.0', '0.0', '0.0', 'NaN', '-0.000735',
        '0.000735'
    ]], "unary float", "tan", half_validation_tolerance=0.016, half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', 
        '0.6279297', '1.255859', '1.884766', '2.511719', '3.140625',
        '3.769531', '4.398438', '5.652344', '6.281250'
    ]], half_outputs=[[
        'NaN', 'NaN', '-0', '-0', '0', '0', 'NaN', 
        '0.72594857', '3.06955433', '-3.07967043', '-0.72892153', '-0.00096773', 
        '0.72596157', '3.07986474', '-0.7304042', '-0.00193546'
    ]])
    add_test_case_float_half('Hcos', ['Hcos'], 'Epsilon', 0.0008,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1']], [[
            'NaN', 'Inf', '1.0', '1.0', '1.0', '1.0', 'Inf', '1.543081',
            '1.543081'
        ]], "unary float", "cosh", half_validation_type='ulp', half_validation_tolerance=2)
    add_test_case_float_half('Hsin', ['Hsin'], 'Epsilon', 0.0008,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1']], [[
            'NaN', '-Inf', '0.0', '0.0', '0.0', '0.0', 'Inf', '1.175201',
            '-1.175201'
        ]], "unary float", "sinh")
    add_test_case_float_half('Htan', ['Htan'], 'Epsilon', 0.0008,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1']], [[
            'NaN', '-1', '-0.0', '-0.0', '0.0', '0.0', '1', '0.761594',
            '-0.761594'
        ]], "unary float", "tanh", warp_version=16202)
    add_test_case_float_half('Acos', ['Acos'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1', '1.5',
        '-1.5'
    ]], [[
        'NaN', 'NaN', '1.570796', '1.570796', '1.570796', '1.570796', 'NaN',
        '0', '3.1415926', 'NaN', 'NaN'
    ]], "unary float", "acos")
    add_test_case_float_half('Asin', ['Asin'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1', '1.5',
        '-1.5'
    ]], [[
        'NaN', 'NaN', '0.0', '0.0', '0.0', '0.0', 'NaN', '1.570796',
        '-1.570796', 'NaN', 'NaN'
    ]], "unary float", "asin")
    add_test_case_float_half('Atan', ['Atan'], 'Epsilon', 0.0008,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1', '-1']], [[
            'NaN', '-1.570796', '0.0', '0.0', '0.0', '0.0', '1.570796',
            '0.785398163', '-0.785398163'
        ]], "unary float", "atan", warp_version=16202)
    add_test_case_float_half('Exp', ['Exp'], 'Relative', 21,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1', '10']],
        [['NaN', '0', '1', '1', '1', '1', 'Inf', '0.367879441', '22026.46579']
         ], "unary float", "exp")
    add_test_case_float_half('Frc', ['Frc'], 'Epsilon', 0.0008, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1', '2.718280',
        '1000.599976', '-7.389'
    ]], [[
        'NaN', 'NaN', '0', '0', '0', '0', 'NaN', '0', '0.718280', '0.599976',
        '0.611'
    ]], "unary float", "frac",
        half_inputs=[['NaN', '-Inf', '0x03FF', '-0', '0', 'Inf', '-1', '2.719',
        '1000.5', '0xC764']],
        half_outputs=[[
         'NaN', 'NaN', '0x03FF', '0', '0', 'NaN', '0', '0.719', '0.5',
        '0x38E1']])
    add_test_case_float_half('Log', ['Log'], 'Relative', 21, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1',
        '2.718281828', '7.389056', '100'
    ]], [[
        'NaN', 'NaN', '-Inf', '-Inf', '-Inf', '-Inf', 'Inf', 'NaN', '1.0',
        '1.99999998', '4.6051701'
    ]],"unary float", "log", half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1',
        '2.719', '7.39', '100'
    ]], half_outputs=[[
        'NaN', 'NaN', '-Inf', '-Inf', '-Inf', '-Inf', 'Inf', 'NaN', '1.0',
        '2', '4.605'
    ]])
    add_test_case_float_half('Sqrt', ['Sqrt'], 'ulp', 1, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1', '2',
        '16.0', '256.0'
    ]], [[
        'NaN', 'NaN', '-0', '-0', '0', '0', 'Inf', 'NaN', '1.41421356237',
        '4.0', '16.0'
    ]], "unary float", "sqrt",
    half_inputs=[['NaN', '-Inf', '-denorm', '-0', '0', '0x03FF', 'Inf', '-1', '2', '16.0', '256.0']],
    half_outputs=[['NaN', 'NaN', 'NaN', '-0', '0', '0x1FFF', 'Inf', 'NaN', '1.41421', '4.0', '16.0']])
    add_test_case_float_half('Rsqrt', ['Rsqrt'], 'ulp', 1, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '-1', '16.0',
        '256.0', '65536.0'
    ]], [[
        'NaN', 'NaN', '-Inf', '-Inf', 'Inf', 'Inf', '0', 'NaN', '0.25',
        '0.0625', '0.00390625'
    ]], "unary float", "rsqrt", half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', '0x03FF', 'Inf', '-1', '16.0',
        '256.0', '0x7bff'
    ]], half_outputs=[[
        'NaN', 'NaN', 'NaN', '-Inf', 'Inf', '0x5801', '0', 'NaN', '0.25',
        '0.0625', '0x1C00'
    ]])
    add_test_case_float_half('Round_ne', ['Round_ne'], 'Epsilon', 0, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '11.5', '-10.0', '-10.4', '-10.5', '-10.6'
    ]], [[
        'NaN', '-Inf', '-0', '-0', '0', '0', 'Inf', '10.0', '10.0', '10.0',
        '11.0', '12.0', '-10.0', '-10.0', '-10.0', '-11.0'
    ]], "unary float", "round")
    add_test_case_float_half('Round_ni', ['Round_ni'], 'Epsilon', 0, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '-10.0', '-10.4', '-10.5', '-10.6'
    ]], [[
        'NaN', '-Inf', '-0', '-0', '0', '0', 'Inf', '10.0', '10.0', '10.0',
        '10.0', '-10.0', '-11.0', '-11.0', '-11.0'
    ]], "unary float", "floor", half_inputs=[[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '-10.0', '-10.4', '-10.5', '-10.6'
    ]], half_outputs=[[
        'NaN', '-Inf', '-1', '-0', '0', '0', 'Inf', '10.0', '10.0', '10.0',
        '10.0', '-10.0', '-11.0', '-11.0', '-11.0'
    ]])
    add_test_case_float_half('Round_pi', ['Round_pi'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '-10.0', '-10.4', '-10.5', '-10.6']],
        [['NaN', '-Inf', '-0', '-0', '0', '0', 'Inf', '10.0', '11.0', '11.0',
        '11.0', '-10.0', '-10.0', '-10.0', '-10.0']], "unary float", "ceil",
        half_inputs=[['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '-10.0', '-10.4', '-10.5', '-10.6']],
        half_outputs=[['NaN', '-Inf', '-0', '-0', '0', '1', 'Inf', '10.0', '11.0', '11.0',
        '11.0', '-10.0', '-10.0', '-10.0', '-10.0']])
    add_test_case_float_half('Round_z', ['Round_z'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '10.0', '10.4',
        '10.5', '10.6', '-10.0', '-10.4', '-10.5', '-10.6']],
        [['NaN', '-Inf', '-0', '-0', '0', '0', 'Inf', '10.0', '10.0', '10.0',
        '10.0', '-10.0', '-10.0', '-10.0', '-10.0']], "unary float", "trunc")
    add_test_case_float_half('IsNaN', ['IsNaN'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0']
         ], [['1', '0', '0', '0', '0', '0', '0', '0', '0']], "unary float bool", "isnan")
    add_test_case_float_half('IsInf', ['IsInf'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0']
         ], [['0', '1', '0', '0', '0', '0', '1', '0', '0']], "unary float bool", "isinf")
    add_test_case_float_half('IsFinite', ['IsFinite'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0']
         ], [['0', '0', '1', '1', '1', '1', '0', '1', '1']], "unary float bool", "isfinite", warp_version=16202)
    add_test_case_float_half('FAbs', ['FAbs'], 'Epsilon', 0,
        [['NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0']
         ], [['NaN', 'Inf', 'denorm', '0', '0', 'denorm', 'Inf', '1', '1']], "unary float", "abs")
    # Binary Float
    add_test_case('FMin', ['FMin','FMax'], 'epsilon', 0, [[
        '-inf', '-inf', '-inf', '-inf', 'inf', 'inf', 'inf', 'inf', 'NaN',
        'NaN', 'NaN', 'NaN', '1.0', '1.0', '-1.0', '-1.0', '1.0'
    ], [
        '-inf', 'inf', '1.0', 'NaN', '-inf', 'inf', '1.0', 'NaN', '-inf',
        'inf', '1.0', 'NaN', '-inf', 'inf', '1.0', 'NaN', '-1.0'
    ]], [[
        '-inf', '-inf', '-inf', '-inf', '-inf', 'inf', '1.0', 'inf', '-inf',
        'inf', '1.0', 'NaN', '-inf', '1.0', '-1.0', '-1.0', '-1.0'
    ], [
        '-inf', 'inf', '1.0', '-inf', 'inf', 'inf', 'inf', 'inf', '-inf',
        'inf', '1.0', 'NaN', '1.0', 'inf', '1.0', '-1.0', '1.0'
    ]], 'cs_6_0', ''' struct SBinaryFPOp {
                float input1;
                float input2;
                float output1;
                float output2;
            };
            RWStructuredBuffer<SBinaryFPOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryFPOp l = g_buf[GI];
                l.output1 = min(l.input1, l.input2);
                l.output2 = max(l.input1, l.input2);
                g_buf[GI] = l;
            };''')
    add_test_case('FMinHalf', ['FMin','FMax'], 'epsilon', 0, [[
        '-inf', '-inf', '-inf', '-inf', 'inf', 'inf', 'inf', 'inf', 'NaN',
        'NaN', 'NaN', 'NaN', '1.0', '1.0', '-1.0', '-1.0', '1.0'
    ], [
        '-inf', 'inf', '1.0', 'NaN', '-inf', 'inf', '1.0', 'NaN', '-inf',
        'inf', '1.0', 'NaN', '-inf', 'inf', '1.0', 'NaN', '-1.0'
    ]], [[
        '-inf', '-inf', '-inf', '-inf', '-inf', 'inf', '1.0', 'inf', '-inf',
        'inf', '1.0', 'NaN', '-inf', '1.0', '-1.0', '-1.0', '-1.0'
    ], [
        '-inf', 'inf', '1.0', '-inf', 'inf', 'inf', 'inf', 'inf', '-inf',
        'inf', '1.0', 'NaN', '1.0', 'inf', '1.0', '-1.0', '1.0'
    ]], 'cs_6_2', ''' struct SBinaryHalfOp {
                half input1;
                half input2;
                half output1;
                half output2;
            };
            RWStructuredBuffer<SBinaryHalfOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryHalfOp l = g_buf[GI];
                l.output1 = min(l.input1, l.input2);
                l.output2 = max(l.input1, l.input2);
                g_buf[GI] = l;
            };''', shader_arguments="-enable-16bit-types")
    add_test_case_float_half('FAdd', ['FAdd'], 'ulp', 1, [['-1.0', '1.0', '32.5', '1.0000001000'],['4', '5.5', '334.7', '0.5000001000']], [['3.0', '6.5', '367.2', '1.5000002000']],
    "binary float", "+")
    add_test_case_float_half('FSub', ['FSub'], 'ulp', 1, [['-1.0', '5.5', '32.5', '1.0000001000'],['4', '1.25', '334.7', '0.5000001000']], [['-5', '4.25', '-302.2', '0.5000']],
    "binary float", "-")
    add_test_case_float_half('FMul', ['FMul'], 'ulp', 1, [['-1.0', '5.5', '1.0000001'],['4', '1.25', '2.0']], [['-4.0', '6.875', '2.0000002']],
    "binary float", "*")
    add_test_case_float_half('FDiv', ['FDiv'], 'ulp', 1, [['-1.0', '5.5', '1.0000001'],['4', '1.25', '2.0']], [['-0.25', '4.4', '0.50000006']],
    "binary float", "/")

    # Denorm Binary Float
    add_test_case_denorm('FAddDenorm', ['FAdd'], 'ulp', 1,
    [['0x007E0000', '0x00200000', '0x007E0000', '0x007E0000'],['0x007E0000','0x00200000', '0x807E0000', '0x800E0000']],
    [['0','0', '0', '0']],
    [['0x00FC0000','0x00400000', '0', '0x00700000']],
    'cs_6_2', get_shader_text("binary float", "+"))
    add_test_case_denorm('FSubDenorm', ['FSub'], 'ulp', 1,
    [['0x007E0000', '0x007F0000', '0x00FF0000', '0x007A0000'],['0x007E0000', '0x807F0000', '0x00800000', '0']],
    [['0x0', '0', '0', '0']],
    [['0x0', '0x00FE0000', '0x007F0000', '0x007A0000']],
    'cs_6_2', get_shader_text("binary float", "-"))
    add_test_case_denorm('FDivDenorm', ['FDiv'], 'ulp', 1,
    [['0x007F0000', '0x807F0000', '0x20000000', '0x00800000'],['1', '4', '0x607F0000', '0x40000000']],
    [['0', '0', '0', '0']],
    [['0x007F0000', '0x801FC000', '0x00101010', '0x00400000']],
    'cs_6_2', get_shader_text("binary float", "/"))
    add_test_case_denorm('FMulDenorm', ['FMul'], 'ulp', 1,
    [['0x00000300', '0x007F0000', '0x007F0000', '0x001E0000', '0x00000300'],['128', '1', '0x007F0000', '20', '0x78000000']],
    [['0', '0', '0', '0', '0']],
    [['0x00018000','0x007F0000', '0', '0x01960000', '0x32400000']],
    'cs_6_2', get_shader_text("binary float", "*"))
    # Tertiary Float
    add_test_case_float_half('FMad', ['FMad'], 'ulp', 1, [[
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0',
        '0', '1', '1.5'
    ], [
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0',
        '0', '1', '10'
    ], [
        'NaN', '-Inf', '-denorm', '-0', '0', 'denorm', 'Inf', '1.0', '-1.0',
        '1', '0', '-5.5'
    ]], [['NaN', 'NaN', '0', '0', '0', '0', 'Inf', '2', '0', '1', '1', '9.5']],
                 "tertiary float", "mad",
    half_inputs=[[
        'NaN', '-Inf', '0x03FF', '-0', '0', 'Inf', '1.0', '-1.0',
        '0', '1', '1.5'
    ], [
        'NaN', '-Inf', '1', '-0', '0', 'Inf', '1.0', '-1.0',
        '0', '1', '10'
    ], [
        'NaN', '-Inf', '0x03FF', '-0', '0', 'Inf', '1.0', '-1.0',
        '1', '0', '-5.5'
    ]],
    half_outputs=[['NaN', 'NaN', '0x07FE', '0', '0', 'Inf', '2', '0', '1', '1', '9.5']])
    # Denorm Tertiary Float
    add_test_case_denorm('FMadDenorm', ['FMad'], 'ulp', 1,
    [['0x80780000', '0x80780000', '0x00780000'],
     ['1', '2', '2'],
     ['0x80780000', '0x00800000', '0x00800000']],
    [['0', '0x00800000', '0x00800000']],
     [['0x80F00000', '0x80700000', '0x01380000']],
                  'cs_6_2', get_shader_text("tertiary float", "mad"))

    # Unary Int
    int8_min, int8_max = '-128', '127'
    int16_min, int16_max = '-32768', '32767'
    int32_min, int32_max = '-2147483648', '2147483647'
    uint16_max = '65535'
    uint32_max = '4294967295'
    add_test_case_int('Bfrev', ['Bfrev'], 'Epsilon', 0, [[
        int32_min, '-65536', '-8', '-1', '0', '1', '8', '65536',
        int32_max
    ]], [[
        '1', '65535', '536870911', '-1', '0', int32_min, '268435456',
        '32768', '-2'
    ]], "unary int", "reversebits",
        input_16=[[int16_min, '-256', '-8', '-1', '0', '1', '8', '256', int16_max]],
        output_16=[['1', '255', '8191', '-1', '0', int16_min, '4096', '128', '-2']])
    # firstbit_shi (s for signed) returns the
    # first 0 from the MSB if the number is negative,
    # else the first 1 from the MSB.
    # all the variants of the instruction return ~0 if no match was found
    add_test_case_int('FirstbitSHi', ['FirstbitSHi'], 'Epsilon', 0, [[
        int32_min, '-65536', '-8', '-1', '0', '1', '8', '65536',
        int32_max
    ]], [['30', '15', '2', '-1', '-1', '0', '3', '16', '30']],
        "unary int", "firstbithigh",
        input_16=[[int16_min, '-256', '-8', '-1', '0', '1', '8', '256', int16_max]],
        output_16=[['14', '7', '2', '-1', '-1', '0', '3', '8', '14']])
    add_test_case_int('FirstbitLo', ['FirstbitLo'], 'Epsilon', 0, [[
        int32_min, '-65536', '-8', '-1', '0', '1', '8', '65536',
        int32_max
    ]], [['31', '16', '3', '0', '-1', '0', '3', '16', '0']],
        "unary int", "firstbitlow",
        input_16=[[int16_min, '-256', '-8', '-1', '0', '1', '8', '256', int16_max]],
        output_16=[['15', '8', '3', '0', '-1', '0', '3', '8', '0']])
    # TODO: there is a known bug in countbits when passing in immediate values.
    # Fix this later
    add_test_case('Countbits', ['Countbits'], 'Epsilon', 0, [[
        int32_min, '-65536', '-8', '-1', '0', '1', '8', '65536',
        int32_max
    ]], [['1', '16', '29', '32', '0', '1', '1', '1', '31']],
         "cs_6_0", get_shader_text("unary int", "countbits"))
    # Unary uint
    add_test_case_int('FirstbitHi', ['FirstbitHi'], 'Epsilon', 0,
                  [['0', '1', '8', '65536', int32_max, uint32_max]],
                  [['-1', '0', '3', '16', '30', '31']],
         "unary uint", "firstbithigh",
        input_16=[['0', '1', '8', uint16_max]],
        output_16=[['-1', '0', '3', '15']])
    # Binary Int
    add_test_case_int('IAdd', ['Add'], 'Epsilon', 0,
                  [[int32_min, '-10', '0', '0', '10', int32_max, '486'],
                   ['0', '10', '-10', '10', '10', '0', '54238']],
                  [[int32_min, '0', '-10', '10', '20', int32_max, '54724']],
            "binary int", "+",
            input_16=[[int16_min, '-10', '0', '0', '10', int16_max],
                      ['0', '10', '-3114', '272', '15', '0']],
            output_16=[[int16_min, '0', '-3114', '272', '25', int16_max]])
    add_test_case_int('ISub', ['Sub'], 'Epsilon', 0,
                  [[int32_min, '-10', '0', '0', '10', int32_max, '486'],
                   ['0', '10', '-10', '10', '10', '0', '54238']],
                  [[int32_min, '-20', '10', '-10', '0', int32_max, '-53752']],
            "binary int", "-",
            input_16=[[int16_min, '-10', '0', '0', '10', int16_max],
                      ['0', '10', '-3114', '272', '15', '0']],
            output_16=[[int16_min, '-20', '3114', '-272', '-5', int16_max]])
    add_test_case_int('IMax', ['IMax'], 'Epsilon', 0,
                  [[int32_min, '-10', '0', '0', '10', int32_max],
                   ['0', '10', '-10', '10', '10', '0']],
                  [['0', '10', '0', '10', '10', int32_max]],
            "binary int call", "max",
            input_16=[[int16_min, '-10', '0', '0', '10', int16_max],
                      ['0', '10', '-3114', '272', '15', '0']],
            output_16=[['0', '10', '0', '272', '15', int16_max]])
    add_test_case_int('IMin', ['IMin'], 'Epsilon', 0,
                  [[int32_min, '-10', '0', '0', '10', int32_max],
                   ['0', '10', '-10', '10', '10', '0']],
                  [[int32_min, '-10', '-10', '0', '10', '0']],
            "binary int call", "min",
            input_16=[[int16_min, '-10', '0', '0', '10', int16_max],
                      ['0', '10', '-3114', '272', '15', '0']],
            output_16=[[int16_min, '-10', '-3114', '0', '10', '0']])
    add_test_case_int('IMul', ['Mul'], 'Epsilon', 0, [
         [ int32_min, '-10', '-1', '0', '1', '10', '10000', int32_max, int32_max ],
         ['-10', '-10', '10', '0', '256', '4', '10001', '0', int32_max]],
         [['0', '100', '-10', '0', '256', '40', '100010000', '0', '1']],
            "binary int", "*",
         input_16=[[ int16_min, '-10', '-1', '0', '1', '10', int16_max],
         ['-10', '-10', '10', '0', '256', '4', '0']],
         output_16=[['0', '100', '-10', '0', '256', '40', '0']])
    add_test_case('IDiv', ['SDiv', 'SRem'], 'Epsilon', 0,
        [['1', '1', '10', '10000', int32_max, int32_max, '-1'],
         ['1', '256', '4', '10001', '2', int32_max, '1']],
        [['1', '0', '2', '0', '1073741823', '1', '-1'],
         ['0', '1', '2', '10000', '1', '0', '0']], "cs_6_0",
        ''' struct SBinaryIntOp {
                int input1;
                int input2;
                int output1;
                int output2;
            };
            RWStructuredBuffer<SBinaryIntOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryIntOp l = g_buf[GI];
                l.output1 = l.input1 / l.input2;
                l.output2 = l.input1 % l.input2;
                g_buf[GI] = l;
            };''')
    add_test_case_int('Shl', ['Shl'], 'Epsilon', 0,
        [['1', '1', '0x1010', '0xa', '-1', '0x12341234', '-1'],
         ['0', '259', '4', '2', '0', '15', '3']],
        [['0x1', '0x8', '0x10100', '0x28', '-1','0x091a0000', '-8']],
        "binary int", "<<",
        input_16=[['1', '1', '0x0101', '0xa', '-1', '0x1234', '-1'],
         ['0', '259', '4', '2', '0', '13', '3']],
        output_16=[['0x1', '0x8', '0x1010', '0x28', '-1','0x8000', '-8']])
    add_test_case_int("LShr", ['LShr'], 'Epsilon', 0,
        [['1', '1', '0xffff', '0x7fffffff', '0x70001234', '0x12340ab3', '0x7fffffff'],
        ['0', '1', '4', '30', '15', '16', '1']],
        [['1', '0', '0xfff', '1', '0xe000', '0x1234', '0x3fffffff']],
        "binary int", ">>",
        input_16=[['1', '1', '0x7fff', '0x7fff'],
        ['0', '1', '4', '14']],
        output_16=[['1', '0', '0x07ff', '1']]
    )
    add_test_case_int("And", ['And'], 'Epsilon', 0,
        [['0x1', '0x01', '0x7fff0000', '0x33333333', '0x137f', '0x12345678', '0xa341', '-1'],
         ['0x1', '0xf0', '0x0000ffff', '0x22222222', '0xec80', '-1', '0x3471', '-1']],
        [['0x1', '0x00', '0x0', '0x22222222', '0x0', '0x12345678', '0x2041', '-1']],
        "binary int", "&",
        input_16=[['0x1', '0x01', '0x7fff', '0x3333', '0x137f', '0x1234', '0xa341', '-1'],
         ['0x1', '0xf0', '0x0000', '0x2222', '0xec80', '-1', '0x3471', '-1']],
        output_16=[['0x1', '0x00', '0x0', '0x2222', '0x0', '0x1234', '0x2041', '-1']],
     )
    add_test_case_int("Or", ['Or'], 'Epsilon', 0,
        [['0x1', '0x01', '0x7fff0000', '0x11111111', '0x137f', '0x0', '0x12345678', '0xa341', '-1'],
         ['0x1', '0xf0', '0x0000ffff', '0x22222222', '0xec80', '0x0', '0x00000000', '0x3471', '-1']],
        [['0x1', '0xf1', '0x7fffffff', '0x33333333', '0xffff', '0x0', '0x12345678', '0xb771', '-1']],
        "binary int", "|",
        input_16=[['0x1', '0x01', '0x7fff', '0x3333', '0x137f', '0x1234', '0xa341', '-1'],
         ['0x1', '0xf0', '0x0000', '0x2222', '0xec80', '0xffff', '0x3471', '-1']],
        output_16=[['0x1', '0xf1', '0x7fff', '0x3333', '0xffff', '0xffff', '0xb771', '-1']],
     )
    add_test_case_int("Xor", ['Xor'], 'Epsilon', 0,
        [['0x1', '0x01', '0x7fff0000', '0x11111111', '0x137f', '0x0', '0x12345678', '0xa341', '-1'],
         ['0x1', '0xf0', '0x0000ffff', '0x22222222', '0xec80', '0x0', '0x00000000', '0x3471', '-1']],
        [['0x0', '0xf1', '0x7fffffff', '0x33333333', '0xffff', '0x0', '0x12345678', '0x9730', '0x00000000']],
        "binary int", "^",
        input_16=[['0x1', '0x01', '0x7fff', '0x1111', '0x137f', '0x0', '0x1234', '0xa341', '-1'],
                  ['0x1', '0xf0', '0x0000', '0x2222', '0xec80', '0x0', '0x0000', '0x3471', '-1']],
        output_16=[['0x0', '0xf1', '0x7fff', '0x3333', '0xffff', '0x0', '0x1234', '0x9730', '0x0000']],
    )

    # Binary Uint
    add_test_case_int('UAdd', ['Add'], 'Epsilon', 0,
                  [['2147483648', '4294967285', '0', '0', '10', int32_max, '486'],
                   ['0', '10', '0', '10', '10', '0', '54238']],
                  [['2147483648', uint32_max, '0', '10', '20', int32_max, '54724']],
                  "binary uint", "+",
                  input_16=[['323', '0xfff5', '0', '0', '10', uint16_max, '486'],
                            ['0', '10', '0', '10', '10', '0', '334']],
                  output_16=[['323', uint16_max, '0', '10', '20', uint16_max, '820']])
    add_test_case_int('USub', ['Sub'], 'Epsilon', 0,
                  [['2147483648', uint32_max, '0', '0', '30', int32_max, '54724'],
                   ['0', '10', '0', '10', '10', '0', '54238']],
                  [['2147483648', '4294967285', '0', '4294967286', '20', int32_max, '486']],
                  "binary uint", "-",
                  input_16=[['323', uint16_max, '0', '0', '10', uint16_max, '486'],
                            ['0', '10', '0', '10', '10', '0', '334']],
                  output_16=[['323', '0xfff5', '0', '-10', '0', uint16_max, '152']])
    add_test_case_int('UMax', ['UMax'], 'Epsilon', 0,
                  [['0', '0', '10', '10000', int32_max, uint32_max],
                   ['0', '256', '4', '10001', '0', uint32_max]],
                  [['0', '256', '10', '10001', int32_max, uint32_max]],
                  "binary uint call", "max",
                  input_16=[['0', '0', '10', '10000', int16_max, uint16_max],
                            ['0', '256', '4', '10001', '0', uint16_max]],
                  output_16=[['0', '256', '10', '10001', int16_max, uint16_max]])
    add_test_case_int('UMin', ['UMin'], 'Epsilon', 0,
                  [['0', '0', '10', '10000', int32_max, uint32_max],
                   ['0', '256', '4', '10001', '0', uint32_max]],
                  [['0', '0', '4', '10000', '0', uint32_max]],
                  "binary uint call", "min",
                  input_16=[['0', '0', '10', '10000', int16_max, uint16_max],
                            ['0', '256', '4', '10001', '0', uint16_max]],
                  output_16=[['0', '0', '4', '10000', '0', uint16_max]])
    add_test_case_int('UMul', ['Mul'], 'Epsilon', 0,
                  [['0', '1', '10', '10000', int32_max],
                   ['0', '256', '4', '10001', '0']],
                  [['0', '256', '40', '100010000', '0']],
                  "binary uint", "*",
                  input_16=[['0', '0', '10', '100', int16_max],
                            ['0', '256', '4', '101', '0']],
                  output_16=[['0', '0', '40', '10100', '0']])
    add_test_case('UDiv', ['UDiv', 'URem'], 'Epsilon', 0,
        [['1', '1', '10', '10000', int32_max, int32_max, '0xffffffff'],
         ['0', '256', '4', '10001', '0', int32_max, '1']],
        [['0xffffffff', '0', '2', '0', '0xffffffff', '1', '0xffffffff'],
         ['0xffffffff', '1', '2', '10000', '0xffffffff', '0', '0']], 'cs_6_0',
        ''' struct SBinaryUintOp {
                uint input1;
                uint input2;
                uint output1;
                uint output2;
            };
            RWStructuredBuffer<SBinaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUintOp l = g_buf[GI];
                l.output1 = l.input1 / l.input2;
                l.output2 = l.input1 % l.input2;
                g_buf[GI] = l;
            };''')
    add_test_case('UAddc', ['UAddc'], 'Epsilon', 0,
        [['1', '1', '10000', '0x80000000', '0x7fffffff', '0xffffffff'],
         ['0', '256', '10001', '1', '0x7fffffff', '0x7fffffff']],
        [['2', '2', '20000', '0', '0xfffffffe', '0xfffffffe'],
         ['0', '512', '20002', '3', '0xfffffffe', '0xffffffff']], 'cs_6_0',
        ''' struct SBinaryUintOp {
                uint input1;
                uint input2;
                uint output1;
                uint output2;
            };
            RWStructuredBuffer<SBinaryUintOp> g_buf : register(u0);
            [numthreads(8,8,1)]
            void main(uint GI : SV_GroupIndex) {
                SBinaryUintOp l = g_buf[GI];
                uint2 x = uint2(l.input1, l.input2);
                uint2 y = AddUint64(x, x);
                l.output1 = y.x;
                l.output2 = y.y;
                g_buf[GI] = l;
            };''')

    # Tertiary Int
    add_test_case_int('IMad', ['IMad'], 'epsilon', 0, [[
        '-2147483647', '-256', '-1', '0', '1', '2', '16', int32_max, '1',
        '-1', '1', '10'
    ], ['1', '-256', '-1', '0', '1', '3', '16', '0', '1', '-1', '10', '100'], [
        '0', '0', '0', '0', '1', '3', '1', '255', '2147483646', '-2147483647',
        '-10', '-2000'
    ]], [[
        '-2147483647', '65536', '1', '0', '2', '9', '257', '255', int32_max,
        '-2147483646', '0', '-1000'
    ]], "tertiary int", "mad",
    input_16=[[int16_min, '-256', '-1', '0', '1', '2', '16', int16_max],
                  ['1','8','-1', '0', '1', '3', '16','1'],
                  ['0', '0', '1', '3', '250', '-30', int16_min, '-50']],
    output_16=[[int16_min, '-2048', '2', '3', '251', '-24', '-32512', '32717']]
    )

    add_test_case_int('UMad', ['UMad'], 'epsilon', 0,
                  [['0', '1', '2', '16', int32_max, '0', '10'], [
                      '0', '1', '2', '16', '1', '0', '10'
                  ], ['0', '0', '1', '15', '0', '10', '10']],
                  [['0', '1', '5', '271', int32_max, '10', '110']],
                  "tertiary uint", "mad",
                  input_16=[['0', '1', '2', '16', int16_max, '0', '10'], [
                      '0', '1', '2', '16', '1', '0', '10'
                  ], ['0', '0', '1', '15', '0', '10', '10']],
                  output_16=[['0', '1', '5', '271', int16_max, '10', '110']],
    )

    # Dot
    add_test_case('Dot', ['Dot2', 'Dot3', 'Dot4'], 'epsilon', 0.008, [[
        'NaN,NaN,NaN,NaN', '-Inf,-Inf,-Inf,-Inf',
        '-denorm,-denorm,-denorm,-denorm', '-0,-0,-0,-0', '0,0,0,0',
        'denorm,denorm,denorm,denorm', 'Inf,Inf,Inf,Inf', '1,1,1,1',
        '-10,0,0,10', 'Inf,Inf,Inf,-Inf'
    ], [
        'NaN,NaN,NaN,NaN', '-Inf,-Inf,-Inf,-Inf',
        '-denorm,-denorm,-denorm,-denorm', '-0,-0,-0,-0', '0,0,0,0',
        'denorm,denorm,denorm,denorm', 'Inf,Inf,Inf,Inf', '1,1,1,1',
        '10,0,0,10', 'Inf,Inf,Inf,Inf'
    ]], [
        [nan, p_inf, 0, 0, 0, 0, p_inf, 2, -100, p_inf],
        [nan, p_inf, 0, 0, 0, 0, p_inf, 3, -100, p_inf],
        [nan, p_inf, 0, 0, 0, 0, p_inf, 4, 0, nan],
    ], 'cs_6_0', ''' struct SDotOp {
                   float4 input1;
                   float4 input2;
                   float o_dot2;
                   float o_dot3;
                   float o_dot4;
                };
                RWStructuredBuffer<SDotOp> g_buf : register(u0);
                [numthreads(8,8,1)]
                void main(uint GI : SV_GroupIndex) {
                    SDotOp l = g_buf[GI];
                    l.o_dot2 = dot(l.input1.xy, l.input2.xy);
                    l.o_dot3 = dot(l.input1.xyz, l.input2.xyz);
                    l.o_dot4 = dot(l.input1.xyzw, l.input2.xyzw);
                    g_buf[GI] = l;
                };''')

    # Dot2AddHalf
    add_test_case('Dot2AddHalf', ['Dot2AddHalf'], 'epsilon', 0.008, [[
        '1,2', '1,-2', '1,2', '-1,2', '1,2', '-1,2', '1,2', '-1,-2',
        '65504,1', '-65504,1', '1,65504', '1,-65504', 'inf,inf',
        'denorm,denorm', '-denorm,-denorm', 'nan,nan'
    ], [
        '3,4', '-3,4', '3,4', '3,-4', '3,4', '-3,4', '3,4', '-3,-4',
        '1,65504', '1,-65504', '65504,1', '-65504,1', 'inf,inf',
        'denorm,denorm', '-denorm,-denorm', 'nan,nan'
    ], [
        '0', '0', '10', '10', '-5', '-5', '-30', '-30', '0', '0',
        '10000000', '-10000000', 'inf', 'denorm', '-denorm',
        'nan'
    ]], [
        [11, -11, 21, -1, 6, 6, -19, -19, 131008, -131008, 10131008,
         -10131008, p_inf, 0, 0, nan],
    ], 'cs_6_4', ''' struct SDot2AddHalfOp {
                   half2 input1;
                   half2 input2;
                   float acc;
                   float result;
                };
                RWStructuredBuffer<SDot2AddHalfOp> g_buf : register(u0);
                [numthreads(8,8,1)]
                void main(uint GI : SV_GroupIndex) {
                    SDot2AddHalfOp l = g_buf[GI];
                    l.result = dot2add(l.input1, l.input2, l.acc);
                    g_buf[GI] = l;
                };''', shader_arguments='-enable-16bit-types')

    # Dot4AddI8Packed
    add_test_case('Dot4AddI8Packed', ['Dot4AddI8Packed'], 'epsilon', 0, [[
        '0x00000102', '0x00000102', '0x00000102', '0x00000102',
        '0XFFFFFFFF', '0x80808080', '0x80808080', '0x807F807F',
        '0x7F7F7F7F', '0x80808080'
    ], [
        '0x00000304', '0x00000304', '0x00000304', '0x00000304',
        '0xFFFFFFFF', '0x01010101', '0x7F7F7F7F', '0x807F807F',
        '0x7F7F7F7F', '0x80808080'
    ], [
        '0', '10', '-5', '-30', '0', '0', '0', '0', '0', '0'
    ]], [
        [11, 21, 6, -19, 4, -512, -65024, 65026, 64516, 65536],
    ], 'cs_6_4', ''' struct SDot4AddI8PackedOp {
                   dword input1;
                   dword input2;
                   int acc;
                   int result;
                };
                RWStructuredBuffer<SDot4AddI8PackedOp> g_buf : register(u0);
                [numthreads(8,8,1)]
                void main(uint GI : SV_GroupIndex) {
                    SDot4AddI8PackedOp l = g_buf[GI];
                    l.result = dot4add_i8packed(l.input1, l.input2, l.acc);
                    g_buf[GI] = l;
                };''')

    # Dot4AddU8Packed
    add_test_case('Dot4AddU8Packed', ['Dot4AddU8Packed'], 'epsilon', 0, [[
        '0x00000102', '0x00000102', '0x01234567', '0xFFFFFFFF',
        '0xFFFFFFFF'
    ], [
        '0x00000304', '0x00000304', '0x23456789', '0xFFFFFFFF',
        '0xFFFFFFFF'
    ], [
        '0', '10', '10000', '0', '3000000000'
    ]], [
        [11, 21, 33668, 260100, 3000260100],
    ], 'cs_6_4', ''' struct SDot4AddU8PackedOp {
                   dword input1;
                   dword input2;
                   dword acc;
                   dword result;
                };
                RWStructuredBuffer<SDot4AddU8PackedOp> g_buf : register(u0);
                [numthreads(8,8,1)]
                void main(uint GI : SV_GroupIndex) {
                    SDot4AddU8PackedOp l = g_buf[GI];
                    l.result = dot4add_u8packed(l.input1, l.input2, l.acc);
                    g_buf[GI] = l;
                };''')

    # Quaternary
    # Msad4 intrinsic calls both Bfi and Msad. Currently this is the only way to call bfi instruction from HLSL
    add_test_case('Bfi', ['Bfi', 'Msad'], 'epsilon', 0,
        [["0xA100B2C3", "0x00000000", "0xFFFF01C1", "0xFFFFFFFF"], [
            "0xD7B0C372, 0x4F57C2A3", "0xFFFFFFFF, 0x00000000",
            "0x38A03AEF, 0x38194DA3", "0xFFFFFFFF, 0x00000000"
        ], ["1,2,3,4", "1,2,3,4", "0,0,0,0", "10,10,10,10"]],
        [['153,6,92,113', '1,2,3,4', '397,585,358,707', '10,265,520,775']],
        'cs_6_0', ''' struct SMsad4 {
                        uint ref;
                        uint2 source;
                        uint4 accum;
                        uint4 result;
                    };
                    RWStructuredBuffer<SMsad4> g_buf : register(u0);
                    [numthreads(8,8,1)]
                    void main(uint GI : SV_GroupIndex) {
                        SMsad4 l = g_buf[GI];
                        l.result = msad4(l.ref, l.source, l.accum);
                        g_buf[GI] = l;
                    };''')

    # Wave Active Tests
    add_test_case('WaveActiveSum', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['2', '4', '8', '-64']], [],
                  'cs_6_0', get_shader_text("wave op int", "WaveActiveSum"))
    add_test_case('WaveActiveProduct', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['1', '2', '4', '-64']], [],
                  'cs_6_0', get_shader_text("wave op int", "WaveActiveProduct"))

    add_test_case('WaveActiveCountBits', ['WaveAllBitCount', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['1', '10', '-4', '-64'],
                   ['-100', '-1000', '300']], [], 'cs_6_0',
                  get_shader_text("wave op int count", "WaveActiveCountBits"))
    add_test_case('WaveActiveMax', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['1', '10', '-4', '-64'],
                   ['-100', '-1000', '300']], [], 'cs_6_0',
                  get_shader_text("wave op int", "WaveActiveMax"))
    add_test_case('WaveActiveMin', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'], ['0'],
                   ['1', '10', '-4', '-64'], ['-100', '-1000', '300']], [],
                  'cs_6_0', get_shader_text("wave op int", "WaveActiveMin"))
    add_test_case('WaveActiveAllEqual', ['WaveActiveAllEqual'], 'Epsilon', 0,
                  [['1', '2', '3', '4', '1', '1', '1', '1'], ['3'], ['-10']],
                  [], 'cs_6_0', get_shader_text("wave op int", "WaveActiveAllEqual"))
    add_test_case('WaveActiveAnyTrue', ['WaveAnyTrue', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '0', '1', '0', '1'], ['1'], ['0']], [], 'cs_6_0',
                  get_shader_text("wave op int", "WaveActiveAnyTrue"))
    add_test_case('WaveActiveAllTrue', ['WaveAllTrue', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '0', '1', '0', '1'], ['1'], ['1']], [], 'cs_6_0',
                  get_shader_text("wave op int", "WaveActiveAllTrue"))

    add_test_case('WaveActiveUSum', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['2', '4', '8', '64']], [],
                  'cs_6_0', get_shader_text("wave op uint", "WaveActiveSum"))
    add_test_case('WaveActiveUProduct', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['1', '2', '4', '64']], [],
                  'cs_6_0', get_shader_text("wave op uint", "WaveActiveProduct"))
    add_test_case('WaveActiveUMax', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4'], ['0'], ['1', '10', '4', '64']], [],
                  'cs_6_0', get_shader_text("wave op uint", "WaveActiveMax"))
    add_test_case('WaveActiveUMin', ['WaveActiveOp', 'WaveReadLaneFirst', 'WaveReadLaneAt'], 'Epsilon', 0,
                  [['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'], ['0'],
                   ['1', '10', '4', '64']], [], 'cs_6_0',
                  get_shader_text("wave op uint", "WaveActiveMin"))
    add_test_case('WaveActiveBitOr', ['WaveActiveBit'], 'Epsilon', 0, [[
        '0xe0000000', '0x0d000000', '0x00b00000', '0x00070000', '0x0000e000',
        '0x00000d00', '0x000000b0', '0x00000007'
    ], ['0xedb7edb7', '0xdb7edb7e', '0xb7edb7ed', '0x7edb7edb'], [
        '0x12481248', '0x24812481', '0x48124812', '0x81248124'
    ], ['0x00000000', '0xffffffff']], [], 'cs_6_0', get_shader_text("wave op uint", "WaveActiveBitOr"))
    add_test_case('WaveActiveBitAnd', ['WaveActiveBit'], 'Epsilon', 0, [[
        '0xefffffff', '0xfdffffff', '0xffbfffff', '0xfff7ffff', '0xffffefff',
        '0xfffffdff', '0xffffffbf', '0xfffffff7'
    ], ['0xedb7edb7', '0xdb7edb7e', '0xb7edb7ed', '0x7edb7edb'], [
        '0x12481248', '0x24812481', '0x48124812', '0x81248124'
    ], ['0x00000000', '0xffffffff']], [], 'cs_6_0', get_shader_text("wave op uint", "WaveActiveBitAnd"))
    add_test_case('WaveActiveBitXor', ['WaveActiveBit'], 'Epsilon', 0, [[
        '0xe0000000', '0x0d000000', '0x00b00000', '0x00070000', '0x0000e000',
        '0x00000d00', '0x000000b0', '0x00000007'
    ], ['0xedb7edb7', '0xdb7edb7e', '0xb7edb7ed', '0x7edb7edb'], [
        '0x12481248', '0x24812481', '0x48124812', '0x81248124'
    ], ['0x00000000', '0xffffffff']], [], 'cs_6_0', get_shader_text("wave op uint", "WaveActiveBitXor"))
    add_test_case('WavePrefixCountBits', ['WavePrefixBitCount'], 'Epsilon', 0,
                  [['1', '2', '3', '4', '5'], ['0'], ['1', '10', '-4', '-64'],
                   ['-100', '-1000', '300']], [], 'cs_6_0',
                  get_shader_text("wave op int count", "WavePrefixCountBits"))
    add_test_case('WavePrefixSum', ['WavePrefixOp'], 'Epsilon', 0,
        [['1', '2', '3', '4', '5'], ['0', '1'], ['1', '2', '4', '-64', '128']],
        [], 'cs_6_0', get_shader_text("wave op int", "WavePrefixSum"))
    add_test_case('WavePrefixProduct', ['WavePrefixOp'], 'Epsilon', 0,
        [['1', '2', '3', '4', '5'], ['0', '1'], ['1', '2', '4', '-64', '128']],
        [], 'cs_6_0', get_shader_text("wave op int", "WavePrefixProduct"))
    add_test_case('WavePrefixUSum', ['WavePrefixOp'], 'Epsilon', 0,
        [['1', '2', '3', '4', '5'], ['0', '1'], ['1', '2', '4', '128']], [],
        'cs_6_0', get_shader_text("wave op uint", "WavePrefixSum"))
    add_test_case('WavePrefixUProduct', ['WavePrefixOp'], 'Epsilon', 0,
        [['1', '2', '3', '4', '5'], ['0', '1'], ['1', '2', '4', '128']], [],
        'cs_6_0', get_shader_text("wave op uint", "WavePrefixProduct"))

    #Wave Multi Prefix Tests
    add_test_case('WaveMultiPrefixBitAnd', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixBitAnd"))
    add_test_case('WaveMultiPrefixBitOr', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixBitOr"))
    add_test_case('WaveMultiPrefixBitXor', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixBitXor"))
    add_test_case('WaveMultiPrefixSum', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixSum"))
    add_test_case('WaveMultiPrefixProduct', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixProduct"))
    add_test_case('WaveMultiPrefixCountBits', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['0', '42', '0', '64', '11', '76', '90', '111', '0', '0', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix int", "WaveMultiPrefixCountBits"))

    add_test_case('WaveMultiPrefixUBitAnd', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixBitAnd"))
    add_test_case('WaveMultiPrefixUBitOr', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixBitOr"))
    add_test_case('WaveMultiPrefixUBitXor', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixBitXor"))
    add_test_case('WaveMultiPrefixUSum', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixSum"))
    add_test_case('WaveMultiPrefixUProduct', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['10', '42', '1', '64', '11', '76', '90', '111', '9', '6', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixProduct"))
    add_test_case('WaveMultiPrefixUCountBits', ['WaveMultiPrefixOp'], 'Epsilon', 0,
         [['0', '3', '1', '5', '4'], ['0', '42', '0', '64', '11', '76', '90', '111', '0', '0', '79', '34']], [],
        'cs_6_5', get_shader_text("wave op multi prefix uint", "WaveMultiPrefixCountBits"))


# generating xml file for execution test using data driven method
# TODO: ElementTree is not generating formatted XML. Currently xml file is checked in after VS Code formatter.
# Implement xml formatter or import formatter library and use that instead.

def generate_parameter_types(table, num_inputs, num_outputs, has_known_warp_issue=False):
    param_types = ET.SubElement(table, "ParameterTypes")
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Target"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Arguments"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Text"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "Validation.Type"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "Validation.Tolerance"
        }).text = "double"
    for i in range(0, num_inputs):
        ET.SubElement(
            param_types,
            "ParameterType",
            attrib={
                "Name": 'Validation.Input{}'.format(i + 1),
                'Array': 'true'
            }).text = "String"
    for i in range(0, num_outputs):
        ET.SubElement(
            param_types,
            "ParameterType",
            attrib={
                "Name": 'Validation.Expected{}'.format(i + 1),
                'Array': 'true'
            }).text = "String"
    if has_known_warp_issue:
        ET.SubElement(param_types, "ParameterType", attrib={"Name":"Warp.Version"}).text = "unsigned int"

def generate_parameter_types_wave(table):
    param_types = ET.SubElement(table, "ParameterTypes")
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Target"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Text"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.NumInputSet"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.InputSet1",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.InputSet2",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.InputSet3",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.InputSet4",
            "Array": "true"
        }).text = "String"

def generate_parameter_types_wave_multi_prefix(table):
    param_types = ET.SubElement(table, "ParameterTypes")

    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Target"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Text"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Keys",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Values",
            "Array": "true"
        }).text = "String"

def generate_parameter_types_msad(table):
    param_types = ET.SubElement(table, "ParameterTypes")
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "ShaderOp.Text"
        }).text = "String"
    ET.SubElement(
        param_types, "ParameterType", attrib={
            "Name": "Validation.Tolerance"
        }).text = "int"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Input1",
            "Array": "true"
        }).text = "unsigned int"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Input2",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Input3",
            "Array": "true"
        }).text = "String"
    ET.SubElement(
        param_types,
        "ParameterType",
        attrib={
            "Name": "Validation.Expected1",
            "Array": "true"
        }).text = "String"

def generate_row(table, case):
    row = ET.SubElement(table, "Row", {"Name": case.test_name})
    ET.SubElement(row, "Parameter", {
        "Name": "Validation.Type"
    }).text = case.validation_type
    ET.SubElement(row, "Parameter", {
        "Name": "Validation.Tolerance"
    }).text = str(case.validation_tolerance)
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Text"
    }).text = case.shader_text
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Target"
    }).text = case.shader_target
    for i in range(len(case.input_lists)):
        inputs = ET.SubElement(row, "Parameter", {
            "Name": "Validation.Input{}".format(i + 1)
        })
        for val in case.input_lists[i]:
            ET.SubElement(inputs, "Value").text = str(val)
    for i in range(len(case.output_lists)):
        outputs = ET.SubElement(row, "Parameter", {
            "Name": "Validation.Expected{}".format(i + 1)
        })
        for val in case.output_lists[i]:
            ET.SubElement(outputs, "Value").text = str(val)
    # Optional parameters
    if case.warp_version > 0:
        ET.SubElement(row, "Parameter", {"Name":"Warp.Version"}).text = str(case.warp_version)
    if case.shader_arguments != "":
        ET.SubElement(row, "Parameter", {"Name":"ShaderOp.Arguments"}).text = case.shader_arguments

def generate_row_wave(table, case):
    row = ET.SubElement(table, "Row", {"Name": case.test_name})
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Name"
    }).text = case.test_name
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Text"
    }).text = case.shader_text
    ET.SubElement(row, "Parameter", {
        "Name": "Validation.NumInputSet"
    }).text = str(len(case.input_lists))
    for i in range(len(case.input_lists)):
        inputs = ET.SubElement(row, "Parameter", {
            "Name": "Validation.InputSet{}".format(i + 1)
        })
        for val in case.input_lists[i]:
            ET.SubElement(inputs, "Value").text = str(val)

def generate_row_wave_multi(table, case):
    row = ET.SubElement(table, "Row", {"Name": case.test_name})
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Name"
    }).text = case.test_name
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Target"
    }).text = case.shader_target
    ET.SubElement(row, "Parameter", {
        "Name": "ShaderOp.Text"
    }).text = case.shader_text
    inputs = ET.SubElement(row, "Parameter", {
        "Name": "Validation.Keys"
    })
    for val in case.input_lists[0]:
        ET.SubElement(inputs, "Value").text = str(val)
    inputs = ET.SubElement(row, "Parameter", {
        "Name": "Validation.Values"
    })
    for val in case.input_lists[1]:
        ET.SubElement(inputs, "Value").text = str(val)

def generate_table_for_taef():
    with open("..\\..\\tools\\clang\\unittests\\HLSL\\ShaderOpArithTable.xml",
              'w') as f:
        tree = ET.ElementTree()
        root = ET.Element('Data')
        # Create tables
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryFloatOpTable"
            }), 1, 1, True)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryFloatOpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryFloatOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryHalfOpTable"
            }), 1, 1, True)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryHalfOpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryHalfOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryIntOpTable"
            }), 1, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryIntOpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryIntOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryInt16OpTable"
            }), 1, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryInt16OpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryInt16OpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryUintOpTable"
            }), 1, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryUintOpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryUintOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "UnaryUint16OpTable"
            }), 1, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "BinaryUint16OpTable"
            }), 2, 2)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "TertiaryUint16OpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "DotOpTable"
            }), 2, 3)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "Dot2AddHalfOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "Dot4AddI8PackedOpTable"
            }), 3, 1)
        generate_parameter_types(
            ET.SubElement(root, "Table", attrib={
                "Id": "Dot4AddU8PackedOpTable"
            }), 3, 1)
        generate_parameter_types_msad(
            ET.SubElement(root, "Table", attrib={
                "Id": "Msad4Table"
            }))
        generate_parameter_types_wave(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsActiveIntTable"
                }))
        generate_parameter_types_wave(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsActiveUintTable"
                }))
        generate_parameter_types_wave(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsPrefixIntTable"
                }))
        generate_parameter_types_wave(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsPrefixUintTable"
                }))
        generate_parameter_types_wave_multi_prefix(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsMultiPrefixIntTable"
                }))
        generate_parameter_types_wave_multi_prefix(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "WaveIntrinsicsMultiPrefixUintTable"
                }))
        generate_parameter_types(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "DenormBinaryFloatOpTable"
                }), 2, 2) # 2 sets of expected values for any mode
        generate_parameter_types(
            ET.SubElement(
                root, "Table", attrib={
                    "Id": "DenormTertiaryFloatOpTable"
                }), 3, 2)

        for case in g_test_cases.values():
            cur_inst = case.insts[0]
            if cur_inst.is_cast or cur_inst.category.startswith("Unary"):
                if "f" in cur_inst.oload_types and not "Half" in case.test_name:
                    generate_row(
                        root.find("./Table[@Id='UnaryFloatOpTable']"),
                        case)
                if "h" in cur_inst.oload_types and "Half" in case.test_name:
                    generate_row(root.find("./Table[@Id='UnaryHalfOpTable']"),case)
                if "i" in cur_inst.oload_types and "Bit16" not in case.test_name:
                    if cur_inst.category.startswith("Unary int"):
                        generate_row(
                            root.find("./Table[@Id='UnaryIntOpTable']"),
                            case)
                    elif cur_inst.category.startswith("Unary uint"):
                        generate_row(
                            root.find("./Table[@Id='UnaryUintOpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)
                if "w" in cur_inst.oload_types and "Bit16" in case.test_name:
                    if cur_inst.category.startswith("Unary int"):
                        generate_row(
                            root.find("./Table[@Id='UnaryInt16OpTable']"),
                            case)
                    elif cur_inst.category.startswith("Unary uint"):
                        generate_row(
                            root.find("./Table[@Id='UnaryUint16OpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)

            elif cur_inst.is_binary or cur_inst.category.startswith(
                    "Binary"):
                if "f" in cur_inst.oload_types and not "Half" in case.test_name:
                    if case.test_name in g_denorm_tests: # for denorm tests
                        generate_row(
                            root.find("./Table[@Id='DenormBinaryFloatOpTable']"),
                            case)
                    else:
                        generate_row(
                            root.find("./Table[@Id='BinaryFloatOpTable']"),
                            case)
                if "h" in cur_inst.oload_types and "Half" in case.test_name:
                    generate_row(root.find("./Table[@Id='BinaryHalfOpTable']"),case)
                if "i" in cur_inst.oload_types and "Bit16" not in case.test_name:
                    if cur_inst.category.startswith("Binary int"):
                        if case.test_name in ['UAdd', 'USub', 'UMul']: # Add, Sub, Mul use same operations for int and uint.
                            generate_row(
                                root.find("./Table[@Id='BinaryUintOpTable']"),
                                case)
                        else:
                            generate_row(
                                root.find("./Table[@Id='BinaryIntOpTable']"),
                                case)
                    elif cur_inst.category.startswith("Binary uint"):
                        generate_row(
                            root.find("./Table[@Id='BinaryUintOpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)
                if "w" in cur_inst.oload_types and "Bit16" in case.test_name:
                    if cur_inst.category.startswith("Binary int"):
                        if case.test_name in ['UAdd', 'USub', 'UMul']: # Add, Sub, Mul use same operations for int and uint.
                            generate_row(
                                root.find("./Table[@Id='BinaryUint16OpTable']"),
                                case)
                        else:
                            generate_row(
                                root.find("./Table[@Id='BinaryInt16OpTable']"),
                                case)
                    elif cur_inst.category.startswith("Binary uint"):
                        generate_row(
                            root.find("./Table[@Id='BinaryUint16OpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)

            elif cur_inst.category.startswith("Tertiary"):
                if "f" in cur_inst.oload_types and not "Half" in case.test_name:
                    if case.test_name in g_denorm_tests: # for denorm tests
                        generate_row(
                            root.find("./Table[@Id='DenormTertiaryFloatOpTable']"),case)
                    else:
                        generate_row(
                            root.find("./Table[@Id='TertiaryFloatOpTable']"),case)
                if "h" in cur_inst.oload_types and "Half" in case.test_name:
                    generate_row(root.find("./Table[@Id='TertiaryHalfOpTable']"),case)
                if "i" in cur_inst.oload_types and "Bit16" not in case.test_name:
                    if cur_inst.category.startswith("Tertiary int"):
                        generate_row(
                            root.find("./Table[@Id='TertiaryIntOpTable']"),
                            case)
                    elif cur_inst.category.startswith("Tertiary uint"):
                        generate_row(
                            root.find(
                                "./Table[@Id='TertiaryUintOpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)
                if "w" in cur_inst.oload_types and "Bit16" in case.test_name:
                    if cur_inst.category.startswith("Tertiary int"):
                        generate_row(
                            root.find("./Table[@Id='TertiaryInt16OpTable']"),
                            case)
                    elif cur_inst.category.startswith("Tertiary uint"):
                        generate_row(
                            root.find(
                                "./Table[@Id='TertiaryUint16OpTable']"),
                            case)
                    else:
                        print("unknown op: " + cur_inst.name)
                        print(cur_inst.dxil_class)
            elif cur_inst.category.startswith("Quaternary"):
                if cur_inst.name == "Bfi":
                    generate_row(
                        root.find("./Table[@Id='Msad4Table']"), case)
                else:
                    print("unknown op: " + cur_inst.name)
                    print(cur_inst.dxil_class)
            elif cur_inst.category == "Dot":
                generate_row(root.find("./Table[@Id='DotOpTable']"), case)
            elif cur_inst.category == "Dot product with accumulate":
                if cur_inst.name == "Dot2AddHalf":
                    generate_row(root.find("./Table[@Id='Dot2AddHalfOpTable']"), case)
                elif cur_inst.name == "Dot4AddI8Packed":
                    generate_row(root.find("./Table[@Id='Dot4AddI8PackedOpTable']"), case)
                elif cur_inst.name == "Dot4AddU8Packed":
                    generate_row(root.find("./Table[@Id='Dot4AddU8PackedOpTable']"), case)
                else:
                    print("unknown op: " + cur_inst.name)
                    print(cur_inst.dxil_class)
            elif cur_inst.dxil_class in ["WaveActiveOp", "WaveAllOp","WaveActiveAllEqual","WaveAnyTrue","WaveAllTrue"]:
                if case.test_name.startswith("WaveActiveU"):
                    generate_row_wave(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsActiveUintTable']"
                        ), case)
                else:
                    generate_row_wave(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsActiveIntTable']"),
                        case)
            elif cur_inst.dxil_class == "WaveActiveBit":
                generate_row_wave(
                    root.find(
                        "./Table[@Id='WaveIntrinsicsActiveUintTable']"),
                    case)
            elif cur_inst.dxil_class == "WavePrefixOp":
                if case.test_name.startswith("WavePrefixU"):
                    generate_row_wave(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsPrefixUintTable']"
                        ), case)
                else:
                    generate_row_wave(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsPrefixIntTable']"),
                        case)
            elif cur_inst.dxil_class == "WaveMultiPrefixOp":
                if case.test_name.startswith("WaveMultiPrefixU"):
                    generate_row_wave_multi(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsMultiPrefixUintTable']"
                        ), case)
                else:
                    generate_row_wave_multi(
                        root.find(
                            "./Table[@Id='WaveIntrinsicsMultiPrefixIntTable']"),
                        case)
            else:
                print("unknown op: " + cur_inst.name)
                print(cur_inst.dxil_class)
        tree._setroot(root)
        from xml.dom.minidom import parseString
        pretty_xml = parseString(ET.tostring(root)).toprettyxml(indent="    ")
        f.write(pretty_xml)

        print("Saved file at: " + f.name)
        f.close()

def print_untested_inst():
    lst = []
    for name in [node.inst.name for node in g_instruction_nodes.values() if len(node.test_cases) == 0]:
        lst += [name]
    lst.sort()
    print("Untested dxil ops: ")
    for name in lst:
        print(name)
    print("Total uncovered dxil ops: " + str(len(lst)))
    print("Total covered dxil ops: " + str(len(g_instruction_nodes)-len(lst)))

# inst name to instruction dict
g_instruction_nodes = {}
# test name to test case dict
g_test_cases = {}

if __name__ == "__main__":
    db = get_db_dxil()
    for inst in db.instr:
        g_instruction_nodes[inst.name] = inst_node(inst)
    add_test_cases()

    args = vars(parser.parse_args())
    mode = args['mode']
    if mode == "info":
        print_untested_inst()
    elif mode == "gen-xml":
        generate_table_for_taef()
    else:
        print("unknown mode: " + mode)
        exit(1)
    exit(0)
